package com.mongodb.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.LookupOperation;
import org.springframework.data.mongodb.core.aggregation.SortOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Component;

import java.beans.Introspector;
import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.regex.Pattern;

/**
 * @author xiaochi
 * @date 2022/8/8 14:04
 * @desc MongoUtil
 */
@Component
public class MongoUtil {

    public static MongoTemplate mongoTemplate;

    @Autowired
    public void setMongoTemplate(MongoTemplate mongoTemplate){
        MongoUtil.mongoTemplate = mongoTemplate;
    }

    /**
     * 创建查询条件 Query
     * @return
     */
    public static Query createQuery(){
        return new Query();
    }

    /**
     * 创建查询条件 Query
     * @param criteria 条件
     * @return
     */
    public static Query createQuery(Criteria criteria){
        return new Query(criteria);
    }

    /**
     * 创建查询条件 Criteria
     * @return
     */
    public static Criteria createCriteria(){
        return new Criteria();
    }

    /** 创建更新条件,批量更新,存在就更新,不存在就插入(适合于每条数据更新条件不一致)
     * 用于放要更新的数据,可以用
     * Update update = MongoUtil.createUpdate();或者Update update = new Update();
     * MongoUtil.getFieldValue(entity).forEach(update::set);
     * @return
     */
    public static Update createUpdate(){
        return new Update();
    }

    /**
     * 创建更新条件,批量更新,存在就更新,不存在就插入(适合于每条数据更新条件不一致)
     * @return
     */
    public static Pair<Query, Update> createPair(Criteria criteria, Update update){
        return Pair.of(Query.query(criteria),update);
    }

    /**
     * 创建更新条件,批量更新,存在就更新,不存在就插入(适合于每条数据更新条件不一致)
     * @return
     */
    public static List<Pair<Query, Update>> newPairList(){
        return new ArrayList<>();
    }

    /**
     * 拼接模糊匹配正则
     * @return
     */
    public static Pattern createLike(Object value){
        return Pattern.compile("^.*" + value + ".*$", Pattern.CASE_INSENSITIVE);
    }

    /**
     * 多表联查条件数组创建
     * 如：List<AggregationOperation> lookupOperationList = MongoUtil.newLookupOperationList();
     * @return
     */
    public static List<AggregationOperation> newLookupOperationList(){
        return new ArrayList<>();
    }

    /**
     * 是否存在
     * @param criteria 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>boolean hasExists(Criteria criteria, Class<T> clazz){
        return hasExists(Query.query(criteria),clazz,null);
    }

    /**
     * 是否存在
     * @param criteria 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>boolean hasExists(Criteria criteria, Class<T> clazz, String collectionName){
        return hasExists(Query.query(criteria),clazz,collectionName);
    }

    /**
     * 是否存在
     * @param query 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>boolean hasExists(Query query, Class<T> clazz){
        return hasExists(query,clazz,null);
    }

    /**
     * 是否存在
     * @param query 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>boolean hasExists(Query query, Class<T> clazz, String collectionName){
        try {
            return Objects.equals(collectionName,null) ? mongoTemplate.exists(query,clazz) : mongoTemplate.exists(query,clazz,collectionName);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 保存(id存在执行更新操作,不存在执行新增操作)
     * @param t 对象
     * @return
     */
    public static <T>T save(T t){
        try {
            return mongoTemplate.save(t);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 保存(id存在执行更新操作,不存在执行新增操作)
     * @param list 对象
     * @return
     */
    public static <T> Collection<T> save(List<T> list){
        try {
            return mongoTemplate.insertAll(list);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 保存(id存在执行更新操作,不存在执行新增操作)
     * @param t 对象
     * @param collectionName 集合名称
     * @return
     */
    public static <T>T save(T t, String collectionName){
        try {
            return mongoTemplate.save(t,collectionName);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 保存(id存在执行更新操作,不存在执行新增操作)
     * @param list 对象
     * @param collectionName 集合名称
     * @return
     */
    public static <T> Collection<T> save(List<T> list, String collectionName){
        try {
            return mongoTemplate.insert(list,collectionName);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 更新
     * @param t 对象
     * @param criteria 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>long update(T t, Criteria criteria, Class<T> clazz){
        return update(t, Query.query(criteria),clazz,null);
    }

    /**
     * 更新
     * @param t 对象
     * @param criteria 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long update(T t, Criteria criteria, Class<T> clazz, String collectionName){
        return update(t, Query.query(criteria),clazz,collectionName);
    }

    /**
     * 更新
     * @param t 对象
     * @param query 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>long update(T t, Query query, Class<T> clazz){
        return update(t,query,clazz,null);
    }

    /**
     * 更新
     * @param t 对象
     * @param query 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long update(T t, Query query, Class<T> clazz, String collectionName){
        try {
            Update update = new Update();
            getFieldValue(t).forEach(update::set);
            return Objects.equals(collectionName,null) ? mongoTemplate.updateFirst(query,update,clazz).getModifiedCount() : mongoTemplate.updateFirst(query,update,clazz,collectionName).getModifiedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 更新
     * @param t 对象
     * @param id 对象id
     * @param clazz 类型
     * @return
     */
    public static <T>long updateById(T t, Serializable id, Class<T> clazz){
        return updateById(t,id,clazz,null);
    }

    /**
     * 更新
     * @param t 对象
     * @param id 对象id
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long updateById(T t, Serializable id, Class<T> clazz, String collectionName){
        try {
            Query query = new Query(Criteria.where("_id").is(id));
            Update update = new Update();
            getFieldValue(t).forEach(update::set);
            return Objects.equals(collectionName,null) ? mongoTemplate.updateFirst(query,update,clazz).getModifiedCount() : mongoTemplate.updateFirst(query,update,clazz,collectionName).getModifiedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 更新
     * @param t 对象
     * @param clazz 类型
     * @return
     */
    public static <T>long updateById(T t, Class<T> clazz){
        return updateById(t,clazz,(String)null);
    }

    /**
     * 更新
     * @param t 对象
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long updateById(T t, Class<T> clazz, String collectionName){
        try {
            Object value = getFieldValueByName("id", t);
            if (Objects.equals(value,null) || "".equals(value)){
                return 0;
            }
            Query query = new Query(Criteria.where("_id").is(value));
            Update update = new Update();
            getFieldValue(t).forEach(update::set);
            return Objects.equals(collectionName,null) ? mongoTemplate.updateFirst(query,update,clazz).getModifiedCount() : mongoTemplate.updateFirst(query,update,clazz,collectionName).getModifiedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 更新多条
     * @param t 对象
     * @param criteria 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>long updateBatch(T t, Criteria criteria, Class<T> clazz){
        return updateBatch(t, Query.query(criteria),clazz,null);
    }

    /**
     * 更新多条
     * @param t 对象
     * @param criteria 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long updateBatch(T t, Criteria criteria, Class<T> clazz, String collectionName){
        return updateBatch(t, Query.query(criteria),clazz,collectionName);
    }

    /**
     * 更新多条
     * @param t 对象
     * @param query 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>long updateBatch(T t, Query query, Class<T> clazz){
        return updateBatch(t,query,clazz,null);
    }

    /**
     * 更新多条
     * @param t 对象
     * @param query 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long updateBatch(T t, Query query, Class<T> clazz, String collectionName){
        try {
            Update update = new Update();
            getFieldValue(t).forEach(update::set);
            return Objects.equals(collectionName,null) ? mongoTemplate.updateMulti(query,update,clazz).getModifiedCount() : mongoTemplate.updateMulti(query,update,clazz,collectionName).getModifiedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 更新多条(适用于每条数据的更新条件不一致,每条数据的Query不一样)
     * @param list 匹配条件与数据集合
     * @param clazz 类型
     * @return
     * 如：List<Pair<Query, Update>> pairList = MongoUtil.newPairList();
     * data.forEach(entity -> {
     *    Criteria c = MongoUtil.createCriteria();
     *    Update update = new Update();
     *    MongoUtil.getFieldValue(entity).forEach(update::set);
     *    pairList.add(MongoUtil.createPair(c,update));
     * });
     * MongoUtil.updateBatch(pairList,t.class);
     */
    public static <T>long updateBatch(List<Pair<Query, Update>> list, Class<T> clazz){
        return updateBatch(list,clazz,null);
    }

    /**
     * 更新多条(适用于每条数据的更新条件不一致,每条数据的Query不一样)
     * @param list 匹配条件与数据集合
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     * 如：List<Pair<Query, Update>> pairList = MongoUtil.newPairList();
     * data.forEach(entity -> {
     *    Criteria c = MongoUtil.createCriteria();
     *    Update update = new Update();
     *    MongoUtil.getFieldValue(entity).forEach(update::set);
     *    pairList.add(MongoUtil.createPair(c,update));
     * });
     * MongoUtil.updateBatch(pairList,t.class);
     */
    public static <T>long updateBatch(List<Pair<Query, Update>> list, Class<T> clazz, String collectionName){
        try {
            BulkOperations bulkOperations = Objects.equals(collectionName,null) ? mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz) : mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz,collectionName);
            return bulkOperations.updateMulti(list).execute().getModifiedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 存在就更新,不存在就插入
     * @param t 对象
     * @param criteria 集合名称
     * @param clazz 类型
     * @return
     */
    public static <T>long insertOrUpdate(T t, Criteria criteria, Class<T> clazz){
        return insertOrUpdate(t,criteria,clazz,null);
    }

    /**
     * 存在就更新,不存在就插入
     * @param t 对象
     * @param criteria 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long insertOrUpdate(T t, Criteria criteria, Class<T> clazz, String collectionName){
        try {
            Update update = new Update();
            getFieldValue(t).forEach(update::set);
            return Objects.equals(collectionName,null) ? mongoTemplate.upsert(Query.query(criteria),update,clazz).getModifiedCount() : mongoTemplate.upsert(Query.query(criteria),update,clazz,collectionName).getModifiedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 批量更新,存在就更新,不存在就插入(适合于每条数据更新条件一致)
     * @param collection 集合
     * @param criteria 匹配条件
     * @param clazz 类型
     * @return collectionName 集合名称
     */
    public static <T>long insertOrUpdate(Collection<T> collection, Criteria criteria, Class<T> clazz){
        return insertOrUpdate(collection, Query.query(criteria),clazz,null);
    }

    /**
     * 批量更新,存在就更新,不存在就插入(适合于每条数据更新条件一致)
     * @param collection 集合
     * @param criteria 匹配条件
     * @param clazz 类型
     * @return collectionName 集合名称
     */
    public static <T>long insertOrUpdate(Collection<T> collection, Criteria criteria, Class<T> clazz, String collectionName){
        return insertOrUpdate(collection, Query.query(criteria),clazz,collectionName);
    }

    /**
     * 批量更新,存在就更新,不存在就插入(适合于每条数据更新条件一致)
     * @param collection 集合
     * @param query 匹配条件
     * @param clazz 类型
     */
    public static <T>long insertOrUpdate(Collection<T> collection, Query query, Class<T> clazz){
        return insertOrUpdate(collection,query,clazz,null);
    }

    /**
     * 批量更新,存在就更新,不存在就插入(适合于每条数据更新条件一致)
     * @param collection 集合
     * @param query 匹配条件
     * @param clazz 类型
     * @return collectionName 集合名称
     */
    public static <T>long insertOrUpdate(Collection<T> collection, Query query, Class<T> clazz, String collectionName){
        try {
            List<Pair<Query, Update>> list = new ArrayList<>(collection.size());
            BulkOperations bulkOperations = Objects.equals(collectionName,null)?mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz):mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz,collectionName);
            for (T t:collection){
                Update update = new Update();
                getFieldValue(t).forEach(update::set);
                list.add(Pair.of(query, update));
            }
            return bulkOperations.upsert(list).execute().getModifiedCount();
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 批量更新,存在就更新,不存在就插入(适合于每条数据更新条件Query不一致)
     * @param updates 匹配条件与数据集合
     * @param clazz 类型
     * 如：List<Pair<Query, Update>> pairList = MongoUtil.newPairList();
     * data.forEach(entity -> {
     *    Criteria c = MongoUtil.createCriteria();
     *    Update update = new Update();
     *    MongoUtil.getFieldValue(entity).forEach(update::set);
     *    pairList.add(MongoUtil.createPair(c,update));
     * });
     * MongoUtil.insertOrUpdate(pairList,t.class);
     */
    public static <T>long insertOrUpdate(List<Pair<Query, Update>> updates, Class<T> clazz){
        return insertOrUpdate(updates,clazz,null);
    }

    /**
     * 批量更新,存在就更新,不存在就插入(适合于每条数据更新条件Query不一致)
     * @param updates 匹配条件与数据集合
     * @param clazz 类型
     * @return collectionName 集合名称
     * 如：List<Pair<Query, Update>> pairList = MongoUtil.newPairList();
     * data.forEach(entity -> {
     *    Criteria c = MongoUtil.createCriteria();
     *    Update update = new Update();
     *    MongoUtil.getFieldValue(entity).forEach(update::set);
     *    pairList.add(MongoUtil.createPair(c,update));
     * });
     * MongoUtil.insertOrUpdate(pairList,t.class);
     */
    public static <T>long insertOrUpdate(List<Pair<Query, Update>> updates, Class<T> clazz, String collectionName){
        try {
            BulkOperations bulkOperations = Objects.equals(collectionName,null)?mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz):mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz,collectionName);
            return bulkOperations.upsert(updates).execute().getModifiedCount();
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 删除
     * @param id 集合id
     * @return
     */
    public static long removeById(Serializable id){
        return removeById(id,null);
    }

    /**
     * 删除
     * @param id 集合id
     * @param collectionName 集合名称
     * @return
     */
    public static long removeById(Serializable id, String collectionName){
        try {
            return Objects.equals(collectionName,null) ? mongoTemplate.remove(id).getDeletedCount() : mongoTemplate.remove(id,collectionName).getDeletedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 删除
     * @param t 对象
     * @return
     */
    public static <T>long removeById(T t){
        try {
            return mongoTemplate.remove(t).getDeletedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 删除
     * @param t 对象
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long removeById(T t, String collectionName){
        try {
            return mongoTemplate.remove(t,collectionName).getDeletedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 删除
     * @param criteria 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>long remove(Criteria criteria, Class<T> clazz){
        return remove(Query.query(criteria),clazz,null);
    }

    /**
     * 删除
     * @param criteria 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long remove(Criteria criteria, Class<T> clazz, String collectionName){
        return remove(Query.query(criteria),clazz,collectionName);
    }

    /**
     * 删除
     * @param query 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>long remove(Query query, Class<T> clazz){
        return remove(query,clazz,null);
    }

    /**
     * 删除
     * @param query 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long remove(Query query, Class<T> clazz, String collectionName){
        try {
            return Objects.equals(collectionName,null) ? mongoTemplate.remove(query,clazz).getDeletedCount() : mongoTemplate.remove(query,clazz,collectionName).getDeletedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 删除(适用于多个不同条件)
     * @param queries 匹配条件集合
     * @param clazz 类型
     * @return
     */
    public static <T>long remove(List<Query> queries, Class<T> clazz){
        return remove(queries,clazz,null);
    }

    /**
     * 删除(适用于多个不同条件)
     * @param queries 匹配条件集合
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long remove(List<Query> queries, Class<T> clazz, String collectionName){
        try {
            BulkOperations bulkOperations = Objects.equals(collectionName,null) ? mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz) : mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, clazz,collectionName);
            return  bulkOperations.remove(queries).execute().getDeletedCount();
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 查询单条
     * @param criteria 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>T findOne(Criteria criteria, Class<T> clazz){
        return findOne(Query.query(criteria),clazz,null);
    }

    /**
     * 查询单条
     * @param criteria 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>T findOne(Criteria criteria, Class<T> clazz, String collectionName){
        return findOne(Query.query(criteria),clazz,collectionName);
    }

    /**
     * 查询单条
     * @param query 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>T findOne(Query query, Class<T> clazz){
        return findOne(query,clazz,null);
    }

    /**
     * 查询单条
     * @param query 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>T findOne(Query query, Class<T> clazz, String collectionName){
        try {
            return Objects.equals(collectionName,null) ? mongoTemplate.findOne(query,clazz) : mongoTemplate.findOne(query,clazz,collectionName);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 查询单条
     * @param id 对象
     * @param clazz 类型
     * @return
     */
    public static <T>T findById(Serializable id, Class<T> clazz){
        try {
            Criteria criteria = Criteria.where("_id").is(id);
            return mongoTemplate.findOne(Query.query(criteria),clazz);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 查询单条
     * @param id 对象
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>T findById(Serializable id, Class<T> clazz, String collectionName){
        try {
            Criteria criteria = Criteria.where("_id").is(id);
            return mongoTemplate.findOne(Query.query(criteria),clazz,collectionName);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 查询多条
     * @param criteria 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T> List<T> find(Criteria criteria, Class<T> clazz){
        return find(Query.query(criteria),clazz,null);
    }

    /**
     * 查询多条
     * @param criteria 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T> List<T> find(Criteria criteria, Class<T> clazz, String collectionName){
        return find(Query.query(criteria),clazz,collectionName);
    }

    /**
     * 查询多条
     * @param criteria 匹配条件
     * @param sort 排序
     * @param clazz 类型
     * @return
     */
    public static <T> List<T> find(Criteria criteria, Sort sort, Class<T> clazz){
        return find(criteria,sort,clazz,null);
    }

    /**
     * 查询多条
     * @param criteria 匹配条件
     * @param sort 排序
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T> List<T> find(Criteria criteria, Sort sort, Class<T> clazz, String collectionName){
        Query query = Query.query(criteria);
        if (!Objects.equals(sort,null)){
            query.with(sort);
        }
        return find(query,clazz,collectionName);
    }

    /**
     * 查询多条
     * @param t 对象
     * @param clazz 类型
     * @return
     */
    public static <T> List<T> find(T t, Class<T> clazz){
        return find(t,null,clazz,null);
    }

    /**
     * 查询多条
     * @param t 对象
     * @param sort 排序
     * @param clazz 类型
     * @return
     */
    public static <T> List<T> find(T t, Sort sort, Class<T> clazz){
        return find(t,sort,clazz,null);
    }

    /**
     * 查询多条
     * @param t 对象
     * @param sort 排序
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T> List<T> find(T t, Sort sort, Class<T> clazz, String collectionName){
        List<T> data = new ArrayList<>();
        try {
            Criteria criteria = null;
            Map<String, Object> fieldValue = getFieldValue(t);
            for (Map.Entry<String, Object> entry : fieldValue.entrySet()){
                if (fieldValue.size() == 1){
                    criteria = Criteria.where(entry.getKey()).is(entry.getValue());
                }else {
                    if (criteria != null){
                        criteria.and(entry.getKey()).is(entry.getValue());
                    }
                }
            }
            if (criteria != null){
                Query query = Query.query(criteria);
                if (!Objects.equals(sort,null)){
                    query.with(sort);
                }
                return find(query,clazz,collectionName);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 查询多条
     * @param query 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T> List<T> find(Query query, Class<T> clazz){
        return find(query,clazz,null);
    }

    /**
     * 查询多条
     * @param query 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T> List<T> find(Query query, Class<T> clazz, String collectionName){
        List<T> data = new ArrayList<>();
        try {
            if (Objects.equals(collectionName,null)){
                data = mongoTemplate.find(query,clazz);
            }else {
                data = mongoTemplate.find(query,clazz,collectionName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 模糊查询
     * @param t 对象
     * @param clazz 类型
     * @return
     */
    public static <T> List<T> findByLike(T t, Class<T> clazz){
        return findByLike(t,clazz,null);
    }

    /**
     * 模糊查询
     * @param t 对象
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T> List<T> findByLike(T t, Class<T> clazz, String collectionName){
        List<T> data = new ArrayList<>();
        try {
            Criteria criteria = null;
            Map<String, Object> fieldValue = getFieldValue(t);
            for (Map.Entry<String, Object> entry :fieldValue.entrySet()){
                // id 不使用模糊查询
                String key = entry.getKey();
                Object value = entry.getValue();
                if("_id".equals(key)){
                    criteria = Criteria.where(key).is(value);
                }else{
                    // 使用模糊查询
                    criteria = Criteria.where(key).regex(".*?" + value + ".*?");
                }
            }
            if (criteria != null){
                data = Objects.equals(collectionName,null) ? mongoTemplate.find(Query.query(criteria),clazz) : mongoTemplate.find(Query.query(criteria),clazz,collectionName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 查询多条
     * @param clazz 类型
     * @return
     */
    public static <T> List<T> findAll(Class<T> clazz){
        return mongoTemplate.findAll(clazz);
    }

    /**
     * 查询多条
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T> List<T> findAll(Class<T> clazz, String collectionName){
        return mongoTemplate.findAll(clazz,collectionName);
    }

    /**
     * 分页查询(PageRequest方式来分页)
     * @param pageNum  当前页
     * @param pageSize 每页数量
     * @param clazz    类型
     * @return
     */
    public static <T> Page<T> pageRequest(int pageNum, int pageSize, Class<T> clazz){
        return pageRequest(pageNum,pageSize,null,null,clazz);
    }

    /**
     * 分页查询(PageRequest方式来分页)
     * @param pageNum  当前页
     * @param pageSize 每页数量
     * @param criteria 匹配条件
     * @param clazz    类型
     * @return
     */
    public static <T>Page<T> pageRequest(int pageNum, int pageSize, Criteria criteria, Class<T> clazz){
        return pageRequest(pageNum,pageSize,criteria,null,clazz);
    }

    /**
     * 分页查询(PageRequest方式来分页)
     * @param pageNum  当前页
     * @param pageSize 每页数量
     * @param sort     排序
     * @param clazz    类型
     * @return
     */
    public static <T>Page<T> pageRequest(int pageNum, int pageSize, Sort sort, Class<T> clazz){
        return pageRequest(pageNum,pageSize,null,sort,clazz);
    }

    /**
     * 分页查询(PageRequest方式来分页)
     * @param pageNum  当前页
     * @param pageSize 每页数量
     * @param criteria 匹配条件
     * @param sort     排序
     * @param clazz    类型
     * @return
     */
    public static <T>Page<T> pageRequest(int pageNum, int pageSize, Criteria criteria, Sort sort, Class<T> clazz){
        PageRequest pageRequest = PageRequest.of(pageNum - 1, pageSize);
        Query query = new Query();
        query.with(pageRequest);
        if (!Objects.equals(sort,null)){
            query.with(sort);
        }
        if (!Objects.equals(criteria,null)){
            query.addCriteria(criteria);
        }
        Page<T> result = new Page<>();
        result.setPageNum(pageNum);
        result.setPageSize(pageSize);
        result.setRows(mongoTemplate.find(query, clazz));
        result.setTotal(mongoTemplate.count(query,clazz));
        return result;
    }

    /**
     * 分页查询
     * @param pageNum   当前页
     * @param pageSize  每页数量
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T>Page<T> page(long pageNum, long pageSize, Class<T> clazz){
        return page(pageNum,pageSize,null,null,clazz);
    }

    /**
     * 分页查询
     * @param pageNum   当前页
     * @param pageSize  每页数量
     * @param criteria  匹配条件
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T>Page<T> page(long pageNum, long pageSize, Criteria criteria, Class<T> clazz){
        return page(pageNum,pageSize,criteria,null,clazz);
    }

    /**
     * 分页查询
     * @param pageNum   当前页
     * @param pageSize  每页数量
     * @param sortOperation 排序字段  Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T> Page<T> page(long pageNum, long pageSize, SortOperation sortOperation, Class<T> clazz){
        return page(pageNum,pageSize,null,sortOperation,clazz);
    }

    /**
     * 分页查询(Aggregation方式分页)
     * @param pageNum   当前页
     * @param pageSize  每个数量
     * @param criteria  匹配条件
     * @param sortOperation 排序字段 Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T>Page<T> page(long pageNum, long pageSize, Criteria criteria, SortOperation sortOperation, Class<T> clazz){
        Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.skip((pageNum - 1) * pageSize),
            Aggregation.limit(pageSize)
        );
        if (!Objects.equals(criteria,null)){
            aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                Aggregation.skip((pageNum - 1) * pageSize),
                Aggregation.limit(pageSize)
            );
        }
        if (!Objects.equals(sortOperation,null)){
            aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria),
                sortOperation,
                Aggregation.skip((pageNum - 1) * pageSize),
                Aggregation.limit(pageSize)
            );
        }
        AggregationResults<T> results = mongoTemplate.aggregate(aggregation, clazz, clazz);
        List<T> data = results.getMappedResults();
        Page<T> result = new Page<>();
        result.setPageNum(pageNum);
        result.setPageSize(pageSize);
        result.setTotal(mongoTemplate.count(Query.query(criteria),clazz));
        result.setRows(data);
        return result;
    }

    /**
     * 多表分页查询(Aggregation方式)
     * @param lookupOperation  联表lookupOperation
     * @param criteria  匹配条件
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T> List<T> marry(LookupOperation lookupOperation, Criteria criteria, Class<T> clazz){
        return marry(lookupOperation,criteria, (SortOperation) null,clazz);
    }

    /**
     * 多表分页查询(Aggregation方式)
     * @param lookupOperation  联表lookupOperation
     * @param criteria  匹配条件
     * @param sort 排序字段 Sort.by(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T>List<T> marry(LookupOperation lookupOperation,Criteria criteria,Sort sort, Class<T> clazz){
        return marry(lookupOperation,criteria,Aggregation.sort(sort),clazz);
    }

    /**
     * 多表分页查询(Aggregation方式)
     * @param lookupOperation  联表lookupOperation
     * @param criteria  匹配条件
     * @param sortOperation 排序字段 Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T> List<T> marry(LookupOperation lookupOperation, Criteria criteria, SortOperation sortOperation, Class<T> clazz){
        Aggregation aggregation = Aggregation.newAggregation(lookupOperation, Aggregation.match(criteria));
        if (!Objects.equals(sortOperation,null)){
            aggregation = Aggregation.newAggregation(
                lookupOperation,
                Aggregation.match(criteria),
                sortOperation
            );
        }
        return mongoTemplate.aggregate(aggregation, clazz, clazz).getMappedResults();
    }

    /**
     * 多表分页查询(Aggregation方式)
     * @param lookupOperations  联表lookupOperation
     * @param criteria  匹配条件
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T> List<T> marry(List<AggregationOperation> lookupOperations, Criteria criteria, Class<T> clazz){
        lookupOperations.add(Aggregation.match(criteria));
        return marry(lookupOperations, clazz);
    }

    /**
     * 多表分页查询(Aggregation方式)
     * @param lookupOperations  联表lookupOperation
     * @param criteria  匹配条件
     * @param sort 排序字段 Sort.by(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     * 如：用法：
     * List<AggregationOperation> lookupOperations = MongoUtil.newLookupOperationList();
     * LookupOperation lookupOperation = LookupOperation.newLookup()
     *     .from("t_group_member")//从表（关联的表）
     *     .localField("groupId")//主表中与从表相关联的字段
     *     .foreignField("groupId")//从表与主表相关联的字段
     *     .as("groups");// 结果集别名,也是从表别名
     * //主表 条件
     * Criteria criteria = Criteria.where("create_user").is(userId);
     * // 从表条件
     * criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
     * lookupOperations.add(lookupOperation);
     * Sort sort = Sort.by(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime));
     * MongoUtil.marry(lookupOperations,criteria,sort,GroupEntity.class);
     */
    public static <T> List<T> marry(List<AggregationOperation> lookupOperations, Criteria criteria, Sort sort, Class<T> clazz){
        lookupOperations.add(Aggregation.match(criteria));
        lookupOperations.add(Aggregation.sort(sort));
        return marry(lookupOperations, clazz);
    }

    /**
     * 多表分页查询(Aggregation方式)
     * @param lookupOperations  联表lookupOperation
     * @param criteria  匹配条件
     * @param sortOperation 排序字段 Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     * 如：用法：
     * List<AggregationOperation> lookupOperations = MongoUtil.newLookupOperationList();
     * LookupOperation lookupOperation = LookupOperation.newLookup()
     *     .from("t_group_member")//从表（关联的表）
     *     .localField("groupId")//主表中与从表相关联的字段
     *     .foreignField("groupId")//从表与主表相关联的字段
     *     .as("groups");// 结果集别名,也是从表别名
     * //主表 条件
     * Criteria criteria = Criteria.where("create_user").is(userId);
     * // 从表条件
     * criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
     * lookupOperations.add(lookupOperation);
     * SortOperation sort = Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime));
     * MongoUtil.marry(lookupOperations,criteria,sort,GroupEntity.class);
     */
    public static <T> List<T> marry(List<AggregationOperation> lookupOperations, Criteria criteria, SortOperation sortOperation, Class<T> clazz){
        lookupOperations.add(Aggregation.match(criteria));
        lookupOperations.add(sortOperation);
        return marry(lookupOperations, clazz);
    }

    /**
     * 多表分页查询(Aggregation方式)
     * @param lookupOperations  联表lookupOperation
     * @param clazz     搜索对象
     * @param <T>
     * @return
     * 封装后用法：
     * List<AggregationOperation> lookupOperations = MongoUtil.newLookupOperationList();
     * 如：工具用法：
     * LookupOperation lookupOperation = LookupOperation.newLookup()
     *     .from("t_group_member")//从表（关联的表）
     *     .localField("groupId")//主表中与从表相关联的字段
     *     .foreignField("groupId")//从表与主表相关联的字段
     *     .as("groups");// 结果集别名,也是从表别名
     * //主表 条件
     * Criteria criteria = Criteria.where("create_user").is(userId);
     * // 从表条件
     * criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
     * lookupOperations.add(lookupOperation);
     * lookupOperations.add(Aggregation.match(criteria));
     * lookupOperations.add(Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime)));
     * MongoUtil.marry(lookupOperations,GroupEntity.class);
     *
     * 原本写法：
     * LookupOperation lookupOperation = LookupOperation.newLookup()
     *     .from("t_group_member")//从表（关联的表）
     *     .localField("groupId")//主表中与从表相关联的字段
     *     .foreignField("groupId")//从表与主表相关联的字段
     *     .as("groups");// 结果集别名,也是从表别名
     * //主表 条件
     * Criteria criteria = Criteria.where("create_user").is(userId);
     * // 从表条件
     * criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
     * //主表
     * AggregationOperation match = Aggregation.match(criteria);
     * SortOperation sort = Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime));
     * Aggregation aggregation = Aggregation.newAggregation(lookupOperation,match,sort);
     * List<GroupEntity> mappedResults = MongoUtil.mongoTemplate.aggregate(aggregation, GroupEntity.class, GroupEntity.class).getMappedResults();
     */
    public static <T> List<T> marry(List<AggregationOperation> lookupOperations, Class<T> clazz){
        /*List<AggregationOperation> lookupOperations = new ArrayList<>();
        LookupOperation lookupOperation = LookupOperation.newLookup()
            .from("t_group_member")//从表（关联的表）
            .localField("groupId")//主表中与从表相关联的字段
            .foreignField("groupId")//从表与主表相关联的字段
            .as("groups");// 结果集别名,也是从表别名
        //主表 条件
        Criteria criteria = Criteria.where("create_user").is(userId);
        // 从表条件
        criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
        SortOperation sort = Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime));
        Aggregation aggregation = Aggregation.newAggregation(
            lookupOperation,
            Aggregation.match(criteria),
            sort
        );
        lookupOperations.add(lookupOperation);*/
        return mongoTemplate.aggregate(Aggregation.newAggregation(lookupOperations), clazz, clazz).getMappedResults();
    }

    /**
     * 多表分页查询(Aggregation方式分页)
     * @param pageNum   当前页
     * @param pageSize  每个数量
     * @param lookupOperation  联表lookupOperation
     * @param criteria  匹配条件
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T>Page<T> marryPage(long pageNum, long pageSize, LookupOperation lookupOperation, Criteria criteria, Class<T> clazz){
        return marryPage(pageNum,pageSize,lookupOperation,criteria,(SortOperation)null,clazz);
    }

    /**
     * 多表分页查询(Aggregation方式分页)
     * @param pageNum   当前页
     * @param pageSize  每个数量
     * @param lookupOperation  联表lookupOperation
     * @param criteria  匹配条件
     * @param sort 排序字段 Sort.by(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T>Page<T> marryPage(long pageNum, long pageSize, LookupOperation lookupOperation, Criteria criteria, Sort sort, Class<T> clazz){
        return marryPage(pageNum,pageSize,lookupOperation,criteria,Aggregation.sort(sort),clazz);
    }

    /**
     * 多表分页查询(Aggregation方式分页)
     * @param pageNum   当前页
     * @param pageSize  每个数量
     * @param lookupOperation  联表lookupOperation
     * @param criteria  匹配条件
     * @param sortOperation 排序字段 Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T>Page<T> marryPage(long pageNum, long pageSize, LookupOperation lookupOperation, Criteria criteria, SortOperation sortOperation, Class<T> clazz){
        List<AggregationOperation> list = new ArrayList<>();
        list.add(lookupOperation);
        return marryPage(pageNum,pageSize,list,criteria,sortOperation,clazz);
    }

    /**
     * 多表分页查询(Aggregation方式分页)
     * @param pageNum   当前页
     * @param pageSize  每个数量
     * @param lookupOperations  联表lookupOperation
     * @param criteria  匹配条件
     * @param clazz     搜索对象
     * @param <T>
     * @return
     */
    public static <T> Page<T> marryPage(long pageNum, long pageSize, List<AggregationOperation> lookupOperations, Criteria criteria, Class<T> clazz){
        return marryPage(pageNum,pageSize,lookupOperations,criteria,(SortOperation)null,clazz);
    }

    /**
     * 多表分页查询(Aggregation方式分页)
     * @param pageNum   当前页
     * @param pageSize  每个数量
     * @param lookupOperations  联表lookupOperation
     * @param criteria  匹配条件
     * @param sort 排序字段 Sort.by(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     * 如：使用：
     * List<AggregationOperation> lookupOperations = MongoUtil.newLookupOperationList();
     * LookupOperation lookupOperation = LookupOperation.newLookup()
     *     .from("t_group_member")//从表（关联的表）
     *     .localField("groupId")//主表中与从表相关联的字段
     *     .foreignField("groupId")//从表与主表相关联的字段
     *     .as("groups");// 结果集别名,也是从表别名
     * //主表 条件
     * Criteria criteria = Criteria.where("create_user").is(userId);
     * // 从表条件
     * criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
     * lookupOperations.add(lookupOperation);
     * long pageNum = 1;
     * long pageSize = 10;
     * Sort sort = Sort.by(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime));
     * MongoUtil.marryPage(pageNum,pageSize,lookupOperations,criteria,sort,GroupEntity.class);
     */
    public static <T>Page<T> marryPage(long pageNum, long pageSize, List<AggregationOperation> lookupOperations, Criteria criteria, Sort sort, Class<T> clazz){
        return marryPage(pageNum,pageSize,lookupOperations,criteria,Aggregation.sort(sort),clazz);
    }

    /**
     * 多表分页查询(Aggregation方式分页)
     * @param pageNum   当前页
     * @param pageSize  每个数量
     * @param lookupOperations  联表lookupOperation
     * @param criteria  匹配条件
     * @param sortOperation 排序字段 Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(sortField))
     * @param clazz     搜索对象
     * @param <T>
     * @return
     * 如：使用：
     * List<AggregationOperation> lookupOperations = MongoUtil.newLookupOperationList();
     * LookupOperation lookupOperation = LookupOperation.newLookup()
     *     .from("t_group_member")//从表（关联的表）
     *     .localField("groupId")//主表中与从表相关联的字段
     *     .foreignField("groupId")//从表与主表相关联的字段
     *     .as("groups");// 结果集别名,也是从表别名
     * //主表 条件
     * Criteria criteria = Criteria.where("create_user").is(userId);
     * // 从表条件
     * criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
     * lookupOperations.add(lookupOperation);
     * long pageNum = 1;
     * long pageSize = 10;
     * SortOperation sort = Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime));
     * MongoUtil.marryPage(pageNum,pageSize,lookupOperations,criteria,sort,GroupEntity.class);
     */
    public static <T>Page<T> marryPage(long pageNum, long pageSize, List<AggregationOperation> lookupOperations, Criteria criteria, SortOperation sortOperation, Class<T> clazz){
        lookupOperations.add(Aggregation.match(criteria));
        if (!Objects.equals(sortOperation,null)){
            // 排序不能添加到最后,否则失效
            lookupOperations.add(sortOperation);
        }
        return marryPage(pageNum,pageSize,lookupOperations,clazz);
    }

    /**
     * 多表分页查询(Aggregation方式分页)
     * @param pageNum   当前页
     * @param pageSize  每个数量
     * @param lookupOperations  联表lookupOperation
     * @param clazz     搜索对象
     * @param <T>
     * @return
     * 如：工具用法：
     * List<AggregationOperation> lookupOperations = MongoUtil.newLookupOperationList();
     * LookupOperation lookupOperation = LookupOperation.newLookup()
     *     .from("t_group_member")//从表（关联的表）
     *     .localField("groupId")//主表中与从表相关联的字段
     *     .foreignField("groupId")//从表与主表相关联的字段
     *     .as("groups");// 结果集别名,也是从表别名
     * //主表 条件
     * Criteria criteria = Criteria.where("create_user").is(userId);
     * // 从表条件
     * criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
     * lookupOperations.add(lookupOperation);
     * lookupOperations.add(Aggregation.match(criteria));
     * lookupOperations.add(Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime)));
     * long pageNum = 1;
     * long pageSize = 10;
     * lookupOperations.add(Aggregation.skip((pageNum - 1) * pageSize));
     * lookupOperations.add(Aggregation.limit(pageSize));
     * MongoUtil.marryPage(lookupOperations,GroupEntity.class);
     *
     * 原本写法：
     * LookupOperation lookupOperation = LookupOperation.newLookup()
     *     .from("t_group_member")//从表（关联的表）
     *     .localField("groupId")//主表中与从表相关联的字段
     *     .foreignField("groupId")//从表与主表相关联的字段
     *     .as("groups");// 结果集别名,也是从表别名
     * //主表 条件
     * Criteria criteria = Criteria.where("create_user").is(userId);
     * // 从表条件
     * criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
     * //主表
     * AggregationOperation match = Aggregation.match(criteria);
     * SortOperation sort = Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime));
     * long pageNum = 1;
     * long pageSize = 10;
     * Aggregation aggregation = Aggregation.newAggregation(lookupOperation,match,sort,Aggregation.skip((pageNum - 1) * pageSize),Aggregation.limit(pageSize));
     * List<GroupEntity> mappedResults = MongoUtil.mongoTemplate.aggregate(aggregation, GroupEntity.class, GroupEntity.class).getMappedResults();
     */
    public static <T>Page<T> marryPage(long pageNum, long pageSize, List<AggregationOperation> lookupOperations, Class<T> clazz){
        /*List<AggregationOperation> lookupOperations = new ArrayList<>();
        LookupOperation lookupOperation = LookupOperation.newLookup()
            .from("t_group_member")//从表（关联的表）
            .localField("groupId")//主表中与从表相关联的字段
            .foreignField("groupId")//从表与主表相关联的字段
            .as("groups");// 结果集别名,也是从表别名
        //主表 条件
        Criteria criteria = Criteria.where("create_user").is(userId);
        // 从表条件
        criteria.andOperator(Criteria.where("groups.user_id").is(userId));// 加上别名
        SortOperation sort = Aggregation.sort(Sort.Direction.DESC, MongoUtil.fnToFieldName(GroupEntity::getUpdateTime));
        Aggregation aggregation = Aggregation.newAggregation(
            lookupOperation,
            Aggregation.match(criteria),
            sort,
            Aggregation.skip((pageNum - 1) * pageSize),
            Aggregation.limit(pageSize)
        );
        lookupOperations.add(lookupOperation);*/
        Aggregation count = Aggregation.newAggregation(lookupOperations);
        int countResult = mongoTemplate.aggregate(count, clazz, clazz).getMappedResults().size();
        lookupOperations.add(Aggregation.skip((pageNum - 1) * pageSize));
        lookupOperations.add(Aggregation.limit(pageSize));
        Aggregation aggregation = Aggregation.newAggregation(lookupOperations);
        List<T> results = mongoTemplate.aggregate(aggregation, clazz, clazz).getMappedResults();
        Page<T> result = new Page<>();
        result.setPageNum(pageNum);
        result.setPageSize(pageSize);
        result.setTotal(countResult);
        result.setRows(results);
        return result;
    }

    /**
     * count统计
     * @param criteria 匹配条件
     * @param collectionName 集合名称
     * @return
     */
    public static long count(Criteria criteria, String collectionName){
        try {
            return mongoTemplate.count(Query.query(criteria),collectionName);
        }catch (Exception e){
            return 0;
        }
    }

    /**
     * count统计
     * @param criteria 匹配条件
     * @param clazz 类型
     * @return
     */
    public static <T>long count(Criteria criteria, Class<T> clazz){
        return count(criteria,clazz,null);
    }

    /**
     * count统计
     * @param criteria 匹配条件
     * @param clazz 类型
     * @param collectionName 集合名称
     * @return
     */
    public static <T>long count(Criteria criteria, Class<T> clazz, String collectionName){
        try {
            return Objects.equals(collectionName,null) ? mongoTemplate.count(Query.query(criteria),clazz) : mongoTemplate.count(Query.query(criteria),clazz,collectionName);
        }catch (Exception e){
            return 0;
        }
    }

    /**
     * 获取实体对象有值的键值对
     * @param o
     * @return
     */
    public static Map<String, Object> getFieldValue(Object o){
        Field[] fields = o.getClass().getDeclaredFields();
        Map<String, Object> map = new HashMap<>();
        for (Field field : fields){
            String key = field.getName();
            if (!Objects.equals("serialVersionUID",key)){
                Object value = getFieldValueByName(key, o);
                if (null != value && !"".equals(value)){
                    map.put(field.getName(),value);
                }
            }
        }
        return map;
    }

    /**
     * 根据实体对象属性名获取属性值
     * @param fieldName
     * @param o
     * @return
     */
    public static Object getFieldValueByName(String fieldName, Object o) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = o.getClass().getMethod(getter, new Class[] {});
            return method.invoke(o, new Object[] {});
        } catch (Exception e) {
            throw new RuntimeException("根据属性名获取属性值异常："+e.getMessage(),e);
        }
    }

    private static final Pattern GET_PATTERN = Pattern.compile("^get[A-Z].*");
    private static final Pattern IS_PATTERN = Pattern.compile("^is[A-Z].*");
    public static <T> String fnToFieldName(Fn<T, Object> fn){
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(true);
            SerializedLambda serializedLambda = ((SerializedLambda) method.invoke(fn));
            String name = serializedLambda.getImplMethodName();
            if (GET_PATTERN.matcher(name).matches()){
                name = name.substring(3);
            }else if (IS_PATTERN.matcher(name).matches()){
                name = name.substring(2);
            }
            return Introspector.decapitalize(name);
        }catch (ReflectiveOperationException e){
            throw new RuntimeException(e);
        }
    }
    public interface Fn<T,R> extends Function<T,R>, Serializable {}

    public static class Page<T>{
        private long pageNum = 1;
        private long pageSize = 10;
        public long total;
        public List<T> rows;

        public Page() {
        }

        public Page(long pageNum, long pageSize, long total, List<T> rows) {
            this.pageNum = pageNum;
            this.pageSize = pageSize;
            this.total = total;
            this.rows = rows;
        }

        public long getPageNum() {
            return pageNum;
        }

        public void setPageNum(long pageNum) {
            this.pageNum = pageNum;
        }

        public long getPageSize() {
            return pageSize;
        }

        public void setPageSize(long pageSize) {
            this.pageSize = pageSize;
        }

        public long getTotal() {
            return total;
        }

        public void setTotal(long total) {
            this.total = total;
        }

        public List<T> getRows() {
            return rows;
        }

        public void setRows(List<T> rows) {
            this.rows = rows;
        }

        @Override
        public String toString() {
            return "Page{pageNum=" + pageNum +", pageSize=" + pageSize +", total=" + total +", rows=" + rows +'}';
        }
    }
}
